#ifndef INC_AABB_H
#define INC_AABB_H

#include "Vector3.h"
#include "Mathutil.h"
#include <vector>

namespace gti
{

class Plane;
class matrix44;

class AABB
{
public:
	AABB();
	AABB(float cx, float cy, float cz, float hx, float hy, float hz);
	AABB(const vector3f& center, const vector3f& halfsize);

	enum CornerId
	{
		LEFT_BOTTOM_BACK=0,		//(-,-,-)=vmin
		LEFT_BOTTOM_FRONT,		//(-,-,+)
		LEFT_TOP_BACK,			//(-,+,-)
		LEFT_TOP_FRONT,			//(-,+,+)
		RIGHT_BOTTOM_BACK,		//(+,-,-)
		RIGHT_BOTTOM_FRONT,		//(+,-,+)
		RIGHT_TOP_BACK,			//(+,+,-)
		RIGHT_TOP_FRONT,		//(+,+,+)=vmax
	};

	enum PlaneId
	{
		RIGHT=0,		// ( 1, 0, 0)
		TOP,			// ( 0, 1, 0)
		FRONT,			// ( 0, 0, 1)
		LEFT,			// (-1, 0, 0)
		BOTTOM,			// ( 0,-1, 0)
		BACK,			// ( 0, 0,-1)
	};

// creation methods
	void set(const vector3f& center, const vector3f& halfsize);
	void set(const vector3f& center, float halfsize);
	void setMinMax(const vector3f& vmin, const vector3f& vmax);

	void expand(float size);
	void extendBy(const vector3f& point);
	void extendBy(const AABB& aabb);
	void transform(const matrix44& mat, AABB& newAABB) const;
	void calcule(const std::vector<vector3f>& positions);

	void getMin(vector3f& vmin) const;
	void getMax(vector3f& vmax) const;
	void getMinMax(vector3f& vmin, vector3f& vmax) const;

	void getCorners(vector3f* corners) const;
	void getCorner(CornerId id, vector3f& corner) const;

	// computes the aabb corner based on the sign of the point components
	void getRelativeCorner(const vector3f& point, vector3f& corner) const;

	// computes the aabb nearest corner based on the input point
	void getNearestCorner(const vector3f& point, vector3f& corner) const;
	void getFurthestCorner(const vector3f& point, vector3f& corner) const;

	void getPlanes(Plane* planes) const;
	void getPlane(PlaneId id, Plane& plane) const;

// precise overlap tests

	// aabb triangle overlap test
	CullFlag overlap(const vector3f &v0,const vector3f &v1,const vector3f &v2) const;
	// aabb aabb overlap test
	CullFlag overlap(const AABB& b) const;
	// aabb sphere overlap test
	CullFlag overlap (const gti::vector3f& center, float radius) const;


// fast overlap tests

	// fast aabb overlap test
	bool collide(const AABB& b) const;

	// aabb triangle (in global coordinates) overlap test
	bool collide(const vector3f &vtx0,const vector3f &vtx1,const vector3f &vtx2) const;
	// aabb triangle (in box coordinates) overlap test
	bool collideTriangleBoxSpace(const vector3f &v0,const vector3f &v1,const vector3f &v2) const;

	// point test
	// hint: call point.inside(aabb) instead
	bool contains(const vector3f& point) const;

// render methods
	void renderWire(const matrix44& vp) const;
	void render() const;

public:
	vector3f center;
	vector3f halfsize;

	// the corners binary table
	static unsigned int corners_table[8][3];
	// the edges of the AABB (without diagonal edges)
	static unsigned int edge_indices[12][2];
	// the edge length can be computed from halfsize[index]*2
	static unsigned int edge_halfsize[12];
	// the edge directions
	static vector3f edge_dir[12];
	// the indices of each quadrant in the AABB
	static unsigned int quad_indices[6][4];
	// the normals of the aabb quadrants
	static float plane_normals[6][3];

};

}; // namespace gti

#endif//INC_AABB_H
